/*
Java board game library.
Copyright (C) 2011  Deepesh Garg

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/


package d.g.boardgames.soccer ;

import java.util.* ;

import d.g.boardgames.Board;
import d.g.boardgames.Cell;
import d.g.boardgames.MoveHelper;
import d.g.boardgames.Ray;
import d.g.boardgames.soccer.Player;


public class SoccerBoard extends Board<SoccerCellState, SoccerMove> {
	enum State {WAITING_, BLUE, RED_BALL, BLUE_BALL} ;
	List<Ray> downRayList ; //allowed moves moving down
	List<Ray> upRayList ; //allowed moves moving up
	List<Ray> ballRayList ; //allowed move for passing ball
	List<Ray> playerBallRayList ; //allowed moves for player possesing ball
	List<Ray> upSnatchRayList ; //
	List<Ray> downSnatchRayList ; //
	
	List<Cell> validMoveList = null ;
	
	Player turn ;
	Player possesBall ;
	boolean playerMoved ;
	boolean ballMoved ;

	public SoccerBoard () {
		super (18, 12) ;
		boardState[1][3] = new SoccerCellState (Player.RED, false) ;
		boardState[1][6] = new SoccerCellState (Player.RED, false) ;
		boardState[3][1] = new SoccerCellState (Player.RED, false) ;
		boardState[3][8] = new SoccerCellState (Player.RED, false) ;
		boardState[4][4] = new SoccerCellState (Player.RED, true) ;
		boardState[13][3] = new SoccerCellState (Player.BLUE, false) ;
		boardState[13][6] = new SoccerCellState (Player.BLUE, false) ;
		boardState[11][1] = new SoccerCellState (Player.BLUE, false) ;
		boardState[11][8] = new SoccerCellState (Player.BLUE, false) ;
		boardState[10][5] = new SoccerCellState (Player.BLUE, false) ;
		initRayList() ;
		turn = Player.RED ;
		possesBall = Player.RED ;
		playerMoved = false ;
		ballMoved = false ;
	}

	public void initRayList () {
		downRayList = new ArrayList<Ray>() ;
		downRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(-1, -1)}))) ;
		downRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(-1, 0)}))) ;
		downRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(-1, 1)}))) ;
		downRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(0, -1)}))) ;
		downRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(0, 1)}))) ;
		downRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(1, -1), new Cell(2, -2)}))) ;
		downRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(1, 0), new Cell(2, 0)}))) ;
		downRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(1, 1), new Cell(2, 2)}))) ;

		upRayList = MoveHelper.invertRayList (downRayList) ;

		ballRayList = new ArrayList<Ray>() ;
		ballRayList.add(new Ray(Arrays.asList(new Cell[] {new Cell(-1,-1), new Cell(-2,-2), new Cell(-3, -3), new Cell(-4,-4), new Cell(-5,-5), new Cell(-6,-6)}))) ;
		ballRayList.add(new Ray(Arrays.asList(new Cell[] {new Cell(-1,0), new Cell(-2,0), new Cell(-3, 0), new Cell(-4,0), new Cell(-5,0), new Cell(-6,0)}))) ;
		ballRayList.add(new Ray(Arrays.asList(new Cell[] {new Cell(-1,1), new Cell(-2,2), new Cell(-3, 3), new Cell(-4,4), new Cell(-5,5), new Cell(-6,6)}))) ;
		ballRayList.add(new Ray(Arrays.asList(new Cell[] {new Cell(0,-1), new Cell(0,-2), new Cell(0, -3), new Cell(0,-4), new Cell(0,-5), new Cell(0,-6)}))) ;
		ballRayList.add(new Ray(Arrays.asList(new Cell[] {new Cell(0,1), new Cell(0,2), new Cell(0, 3), new Cell(0,4), new Cell(0,5), new Cell(0,6)}))) ;
		ballRayList.add(new Ray(Arrays.asList(new Cell[] {new Cell(1,-1), new Cell(2,-2), new Cell(3, -3), new Cell(4,-4), new Cell(5,-5), new Cell(6,-6)}))) ;
		ballRayList.add(new Ray(Arrays.asList(new Cell[] {new Cell(1,0), new Cell(2,0), new Cell(3, 0), new Cell(4,0), new Cell(5,0), new Cell(6,0)}))) ;
		ballRayList.add(new Ray(Arrays.asList(new Cell[] {new Cell(1,1), new Cell(2,2), new Cell(3, 3), new Cell(4,4), new Cell(5,5), new Cell(6,6)}))) ;

		playerBallRayList = new ArrayList<Ray>() ;
		playerBallRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(-1, -1)}))) ;
		playerBallRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(-1, 0)}))) ;
		playerBallRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(-1, 1)}))) ;
		playerBallRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(0, -1)}))) ;
		playerBallRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(0, 1)}))) ;
		playerBallRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(1, -1)}))) ;
		playerBallRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(1, 0)}))) ;
		playerBallRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(1, 1)}))) ;

		upSnatchRayList = new ArrayList<Ray>() ;
		upSnatchRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(0, -1)}))) ;
		upSnatchRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(-1, -1)}))) ;
		upSnatchRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(-1, 0)}))) ;
		upSnatchRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(-1, 1)}))) ;
		upSnatchRayList.add( new Ray(Arrays.asList( new Cell[] {new Cell(0, 1)}))) ;

		downSnatchRayList = MoveHelper.invertRayList (upSnatchRayList) ;
	}

	private void checkPass() {
		if (turn == possesBall) {
			List<Ray> snatchList = getCurrentSnatchList() ;
			Cell bCell = whereIsBall() ;
			SoccerCellState snatchFromCellState = getCellState(bCell.getRow(), bCell.getCol()) ;
			List<Cell> possibleSnatch = MoveHelper.getAllowedNonEmpty(this, snatchList, bCell) ;
			for (Cell c: possibleSnatch) {
				SoccerCellState snatchToCellState = getCellState(c.getRow(), c.getCol()) ;
				if (snatchToCellState.getPlayer() != turn) {
					snatchFromCellState.setPossesBall(false) ;
					snatchToCellState.setPossesBall(true) ;
					possesBall = snatchToCellState.getPlayer() ;
					break ;
				}
			}
		}
	}

	public void actionFromCell (Cell fromCell) {
		SoccerCellState cellFromState =  getCellState(fromCell) ;
		Player thisCellPlayer ;
		thisCellPlayer = cellFromState.getPlayer() ;
		if (turn == thisCellPlayer) {
			List<Cell> allowedMoves ;
			if (cellFromState.getPossesBall()) {
				allowedMoves = MoveHelper.getAllowedEmpty (this, playerBallRayList, fromCell) ;
				List<Cell> allowedPass = MoveHelper.getAllowedNonEmpty (this, ballRayList, fromCell) ;
				for (Cell passCell: allowedPass) {
					SoccerCellState passCellState =  getCellState (passCell) ;
					if (cellFromState.getPlayer() == passCellState.getPlayer()) {
						allowedMoves.add(passCell) ;
					}
				}
			} else {
				allowedMoves = MoveHelper.getAllowedEmpty (this, getCurrentRayList(), fromCell) ;
			}
			validMoveList = allowedMoves ;
		} else {
			validMoveList = null ;
		}
	}
	
	public void actionToCell (Cell cellFrom, Cell cellTo) {
		boolean success = false ;
		boolean changePlayer = false ;
		SoccerCellState cellFromState = getCellState(cellFrom) ;
		SoccerCellState cellToState =  getCellState(cellTo) ;
		Player thisCellPlayer ;
		if (cellFromState == null) {
			return ;
		}
		thisCellPlayer = cellFromState.getPlayer() ;

		if (turn == thisCellPlayer) {
			//check if player is moving
			if (cellToState == null && playerMoved == false && (!cellFromState.getPossesBall() || !ballMoved)) {
				List<Cell> allowedMoves ;
				if (cellFromState.getPossesBall()) {
					allowedMoves = MoveHelper.getAllowedEmpty (this, playerBallRayList, cellFrom) ;
				} else {
					allowedMoves = MoveHelper.getAllowedEmpty (this, getCurrentRayList(), cellFrom) ;
				}
				if (allowedMoves.contains(cellTo)) {
					setCellState(cellTo, getCellState(cellFrom)) ;
					setCellState(cellFrom, null) ;
					playerMoved = true ;
					if (cellFromState.getPossesBall()) {
						ballMoved = true ;
					}
				}
			}
			//check if its a pass
			if (cellToState != null) {
				List<Cell> allowedMoves = MoveHelper.getAllowedNonEmpty (this, ballRayList, cellFrom) ;
				if (allowedMoves.contains(cellTo)) {
					if (cellFromState.getPlayer() == cellToState.getPlayer() && cellFromState.getPossesBall() == true) {
					cellFromState.setPossesBall(false) ;
					cellToState.setPossesBall(true) ;
					ballMoved = true ;
					}
				}
				if (cellFrom.equals(cellTo)) {
					ballMoved = true ;
				}
			}
			success = true ;
		}
		if (playerMoved && ballMoved) {
			checkPass() ;
			if (turn == Player.RED) {
				turn = Player.BLUE ;
			} else {
				turn = Player.RED ;
			}
			playerMoved = false ;
			if (turn == possesBall) {
				ballMoved = false ;
			}
		}
		validMoveList = null ;
		return  ;		
	}
	
	private List<Ray> getCurrentRayList() {
		if (possesBall == Player.RED)
			return downRayList ;
		return upRayList ;
	}

	private List<Ray> getCurrentSnatchList() {
		if (possesBall == Player.RED)
			return downSnatchRayList ;
		return upSnatchRayList ;
	}

	private Cell whereIsBall() {
		for (int row = 0; row < getRowCount(); row++) {
			for (int col = 0; col < getColCount(); col++) {
				SoccerCellState state = getCellState(row, col) ; 			
				if (state != null) {
					if (state.getPossesBall() == true) {
						return new Cell(row, col) ;
					}
				}
			}
		}
		return null ;
	}
	
	public List<Cell> getValidMoveList() {
		return validMoveList ;
	}
	
	public SoccerBoard clone() {
		return null;
	}
}
